# 在此处创建你的视图
import django_filters
from celery import chain
from django.http import Http404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

from Admin.models import RemoteProblem
from Admin.serializers.RemoteProblem import RemoteProblemSerializer
from Person.authenticate import MyJSONWebTokenAuthentication
from Person.models import Person
from Problems.models import Problem
from Problems.serializers import ProblemSerializer, ProblemDetailSerializer
from Robots.RobotFactory import RobotFactory
from Robots.models import RemoteOJ
from Submission.config import Verdict
from Submission.models import Submission
from Utils.BasePageNumberPagination import MyBasePageNumberPagination
from Utils.BaseResponse import BaseResponse
from Utils.GetUserFromToken import get_username_from_request
from .tasks import submit_code_to_remote_robot, get_submission_result, analyze_submission


# Problem模型的集合操作API视图
class ProblemAPIView(APIView):
    """
    Problem对象集合操作视图，提供获取所有Problem对象和创建新的Problem对象功能
    """

    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了
    pagination_class = MyBasePageNumberPagination

    # GET 方法：获取所有Problem对象
    def get(self, request, format=None, *args, **kwargs):
        """
        获取所有Problem对象信息
        :param request: 请求对象，包含请求信息
        :param format: 请求的数据格式，默认为None，允许客户端指定返回数据的格式
        :param args: 位置参数
        :param kwargs: 关键字参数
        :return: 返回包含所有Problem对象序列化数据的成功响应
        """

        # show_all_problems()
        # 获取所有Problem对象实例
        problem_list = Problem.objects.all()
        # 序列化所有Problem对象
        serializer = ProblemSerializer(problem_list, many=True)
        # 返回序列化后的Problem数据
        return BaseResponse({"count": len(problem_list), "list": serializer.data}, status=status.HTTP_200_OK).success()

    # POST 方法：创建新的Problem对象
    def post(self, request, format=None, *args, **kwargs):
        """
        创建新的Problem对象
        :param request: 请求对象，包含待创建的Problem对象数据
        :request.data 格式示例:
        {
            "title": "A + B + C Problem",
            "time_limit": "1s",
            "memory_limit": "1024MB",
            "is_spj": false,
            "remote_oj": 2,
            "remote_id": "5A"
        }
        :return: 如果数据有效且保存成功，返回创建的Problem对象序列化数据以及201 CREATED状态码；否则返回400 BAD REQUEST状态码和错误信息
        """
        # 创建并初始化Problem序列化器
        serializer = ProblemSerializer(data=request.data)
        # 验证并保存Problem信息
        if serializer.is_valid():
            serializer.save()
            # 保存成功，返回新建Problem的数据及成功消息
            return BaseResponse(serializer.data, status=status.HTTP_201_CREATED).success()
        # 验证失败，返回错误信息及400 BAD REQUEST状态码
        return BaseResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST).fail("不合法的数据")


# Problem模型详情操作API视图
class ProblemDetailAPIView(APIView):
    """
    Problem对象详情操作视图，提供检索、更新和删除单个Problem对象的功能
    """

    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    # 检查用户是否有权限访问或修改Problem对象（暂时为空）
    def check_user_permission(self, problem, request):
        pass

    # 根据主键获取Problem对象
    def get_object(self, pk):
        """
        根据给定主键获取Problem对象
        :param pk: Problem对象的主键
        :return: 找到的Problem对象，若未找到则抛出Http404异常
        """
        try:
            return Problem.objects.get(pk=pk)
        except Problem.DoesNotExist:
            raise Http404

    # GET 方法：获取单个Problem对象
    def get(self, request, pk, format=None):
        """
        获取单个Problem对象信息
        :param request: 请求对象，包含请求信息
        :param pk: 需要获取的Problem对象的主键
        :param format: 请求的数据格式，默认为None，允许客户端指定返回数据的格式
        :return: 如果找到对应Problem对象，则返回其序列化后的信息以及200 OK状态码；否则返回404 NOT FOUND状态码及错误信息
        """
        try:
            # 根据主键获取Problem对象
            problem = self.get_object(pk)
        except Http404:
            # Problem对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 序列化并返回Problem对象信息
        serializer = ProblemDetailSerializer(problem)
        return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()

    # PUT 方法：更新单个Problem对象
    def put(self, request, pk, format=None):
        """
        更新单个Problem对象信息
        :param request: 请求对象，包含待更新的Problem对象数据
        :param pk: 需要更新的Problem对象的主键
        :param format: 请求的数据格式，默认为None，允许客户端指定发送数据的格式
        :return: 如果数据有效且更新成功，返回更新后的Problem对象序列化数据以及200 OK状态码；否则返回400 BAD REQUEST状态码和错误信息
        """
        try:
            # 根据主键获取Problem对象
            problem = self.get_object(pk)
        except Http404:
            # Problem对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 更新并验证Problem信息
        serializer = ProblemSerializer(problem, data=request.data)
        if serializer.is_valid():
            serializer.save()
            # 更新成功，返回更新后的Problem数据及成功消息
            return BaseResponse(serializer.data, status=status.HTTP_200_OK).success()
        # 更新失败，返回错误信息及400 BAD REQUEST状态码
        return BaseResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST).fail("不合法的数据")

    # DELETE 方法：删除单个Problem对象
    def delete(self, request, pk, format=None):
        """
        删除单个Problem对象
        :param request: 请求对象，包含删除请求信息
        :param pk: 需要删除的Problem对象的主键
        :param format: 请求的数据格式，默认为None，此方法不受此参数影响
        :return: 如果删除成功，则返回204 NO CONTENT状态码；否则返回404 NOT FOUND状态码及错误信息
        """
        try:
            # 根据主键获取Problem对象
            problem = self.get_object(pk)
        except Http404:
            # Problem对象不存在，返回错误信息及状态码
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(f"对象不存在,不合法的 pk:{pk}")

        # 删除Problem对象
        problem.delete()
        # 返回删除成功的消息及204 NO CONTENT状态码
        return BaseResponse(status=status.HTTP_204_NO_CONTENT).success()


class ProblemGet(APIView):
    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    def get(self, request, problem_code):
        remote_oj_list = RemoteOJ.objects.all()
        problem_serializer = None

        for oj in remote_oj_list:
            if oj.name in problem_code:
                robot = RobotFactory.create_robot(oj.name, get_problem=True)
                try:
                    problem_serializer = robot.get_problem(problem_code)
                except Exception as e:
                    return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail(str(e))
                else:
                    break
                finally:
                    if robot.username is not None:
                        robot.save()
                    robot.release()
                    del robot
        if not problem_serializer:
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail("题目不存在")


        remote_problem = RemoteProblem.objects.filter(remote_oj=oj, remote_id=problem_serializer['remote_id']).first()
        if remote_problem:
            remote_problem.is_get_problem_success = True
            remote_problem.save()


        return BaseResponse(problem_serializer, status=status.HTTP_200_OK).success()


class SubmitAPIView(APIView):
    authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    permission_classes = [IsAuthenticated]  # 配置了权限类，没登录的就没有权限访问了

    def post(self, request):
        submit = request.data

        username = get_username_from_request(request.headers.get('Authorization'))
        if username is None:
            return BaseResponse(status=status.HTTP_401_UNAUTHORIZED).fail("提交用户不存在")
        try:
            problem = Problem.objects.get(pk=submit['problemId'])
        except Problem.DoesNotExist:
            return BaseResponse(status=status.HTTP_404_NOT_FOUND).fail("提交题目不存在")
        if len(submit["code"]) >= 4096:
            return BaseResponse(status=status.HTTP_400_BAD_REQUEST).fail("代码长度不能超过4k")

        submission = Submission.objects.create(
            user=Person.objects.get(username=username),
            problem=problem,
            code=submit["code"],
            verdict=Verdict.PENDING,
            lang=submit["lang"]
        )



        submit_data = {"lang": submit["lang"], "code": submit["code"], "submission_id": submission.id}
        problem_data = {"remote_oj": {"name": problem.remote_oj.name}, "remote_id": problem.remote_id}

        chain(
            submit_code_to_remote_robot.si(submit_data, problem_data),
            get_submission_result.si(submission.id, problem_data["remote_id"])
        ).delay()

        analyze_submission.delay(submission.id , submit["code"])


        return BaseResponse(data={"submissionId": submission.pk}, status=status.HTTP_200_OK).success("提交成功")


class ProblemAdmin(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Problem.objects.all()
    serializer_class = ProblemSerializer
    # authentication_classes = [MyJSONWebTokenAuthentication]  # 登录认证
    # permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend,]
    filterset_fields = ['id', 'remote_oj']
    pagination_class = MyBasePageNumberPagination  # 使用分页器

    def get(self, request, format=None):
        res = self.list(request)
        if res.status_code == 200:
            return BaseResponse(data=res.data, status=status.HTTP_200_OK).success()
        return BaseResponse(data=res.data, status=status.HTTP_400_BAD_REQUEST).fail()

    def post(self, request, format=None):
        res = self.create(request)
        if res.status_code == status.HTTP_201_CREATED:
            return BaseResponse(data=res.data, status=status.HTTP_201_CREATED).success()
        return BaseResponse(data=res.data, status=status.HTTP_400_BAD_REQUEST).fail()
